package com.zxd.interview.eightthread.threadobjectclasscommonmethod;

/**
 * notify和NotifyAll 演示
 * 线程1和线程2被阻塞，线程3负责唤醒
 * @description: notify和NotifyAll 演示
 * @author Xander
 * @date 2023/3/12 11:44
 * @version 1.0
 */

public class WaitNotifyAll {


    public static Object object = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread1 thread2 = new Thread1();
        thread2.setName("Thread_B");
        thread2.start();

        Thread1 thread1 = new Thread1();
        thread1.setName("Thread_A");
        thread1.start();
//        Thread.sleep(100);

        // 这里不进行等待，即使调用 notifyAll 也有可能存在问题
//        Thread.sleep(200);
        Thread3 thread3 = new Thread3();
        thread3.setName("Thread_C");
        thread3.start();
    }/**
     如果调用notify，只能唤醒第一个wait的对象

     运行结果：
     线程Thread-0 开始执行
     线程Thread-0 进入wait()
     线程Thread-1 开始执行
     线程Thread-1 进入wait()
     线程Thread-2 调用了notify
     线程Thread-0 被唤醒，继续执行
     线程Thread-0 获取到了锁，执行完成

     设置线程名称之后，实际上NotifyALL唤醒的是随机的，随着CPU的排序会出现不同情况。
     线程Thread_B 开始执行
     线程Thread_B 进入wait()
     线程Thread_A 开始执行
     线程Thread_A 进入wait()
     线程Thread_C 调用了notify
     线程Thread_B 被唤醒，继续执行
     线程Thread_B 获取到了锁，执行完成

     如果三个线程都不进行等待，即使调用 notifyAll 也有可能存在问题

     线程Thread_B 开始执行
     线程Thread_B 进入wait()
     线程Thread_A 开始执行
     线程Thread_A 进入wait()
     线程Thread_C 调用了 notifyAll()
     线程Thread_A 被唤醒，继续执行
     线程Thread_A 获取到了锁，执行完成
     线程Thread_B 被唤醒，继续执行
     线程Thread_B 获取到了锁，执行完成

     线程Thread_B 开始执行
     线程Thread_B 进入wait()
     线程Thread_A 开始执行
     线程Thread_A 进入wait()
     线程Thread_C 调用了 notifyAll()
     线程Thread_A 被唤醒，继续执行
     线程Thread_A 获取到了锁，执行完成
     线程Thread_B 被唤醒，继续执行
     线程Thread_B 获取到了锁，执行完成

     */


    static class Thread1 extends Thread {

        @Override
        public void run() {
            synchronized (object) {
                System.out.println("线程" + Thread.currentThread().getName() +  " 开始执行");
                try {
                    System.out.println("线程" + Thread.currentThread().getName() +  " 进入wait()");
                    object.wait();
                    System.out.println("线程" + Thread.currentThread().getName() +  " 被唤醒，继续执行");
                } catch (InterruptedException e) {
                    // 中断异常
                    e.printStackTrace();
                }
                System.out.println("线程" + Thread.currentThread().getName() + " 获取到了锁，执行完成");
            }
        }
    }

    static class Thread3 extends Thread {
        @Override
        public void run() {
            try {
                synchronized (object) {
                    Thread.sleep(1000);
//                    object.notify();
//                    System.out.println("线程" + Thread.currentThread().getName() + " 调用了notify");
                    // 唤醒所有线程
                    object.notifyAll();
                    System.out.println("线程" + Thread.currentThread().getName() + " 调用了 notifyAll()");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
